/******************************************************************************
 *  Project:		Neddle Community Edition
 *  Filename:		CollectionExtensions.cs
 *	Created By:     Kristopher Cargile <kristopher@neddle.org>
 *  Date Created:	March 29, 2011
 * ****************************************************************************
 * IMPORTANT GNU LICENSE INFORMATION. DO NOT REMOVE THIS SECTION!
 * 
 * Neddle :: Copyright (c) 2010-2012, Cargile Technology Group, LLC
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 ******************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Neddle
{
    /// <summary>
    /// CollectionExtensions
    /// </summary>
    public static class CollectionExtensions
    {
        /// <summary>
        /// Returns as collection.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection">The collection.</param>
        /// <returns></returns>
        public static ICollection<T> AsCollection<T>(this IEnumerable<T> collection)
        {
            return (ICollection<T>) collection;
        }

        /// <summary>
        /// Checks if empty.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="message">The message.</param>
        public static void CheckIfEmpty<T>(this ICollection<T> collection, string message)
        {
            if (collection.Count == 0)
            {
                throw new InvalidOperationException(message);
            }
        }

        /// <summary>
        /// iterate collection and execute the delegate.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="del">The del.</param>
        public static void ForEach<T>(this IEnumerable<T> collection, Action<T> del)
        {
            foreach(T t in collection)
            {
                del(t);
            }
        }

        /// <summary>
        /// Adds the range to the collection.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="toAdd">To add.</param>
        public static void AddRange<T>(this IList<T> collection, IEnumerable<T> toAdd)
        {
            if (toAdd == null || !toAdd.Any()) return;

            BindingList<T> bl = collection as BindingList<T>;
            if (bl != null)
                bl.RaiseListChangedEvents = false;
            foreach (T t in toAdd)
            {
                collection.Add(t);
            }
            if (bl != null)
            {
                bl.RaiseListChangedEvents = true;
                bl.ResetBindings();
            }
        }

        /// <summary>
        /// Check if all the element has a common factor provided by the expression
        /// </summary>
        /// <typeparam name="TOwner">The type of the owner.</typeparam>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        public static IEnumerable<TItem> Common<TOwner, TItem>(this IEnumerable<TOwner> collection, Func<TOwner, IEnumerable<TItem>> expression)
        {
            return from o in collection
                   from i in expression(o)
                   group i by i
                   into itemGroup
                       where itemGroup.Count() == collection.Count()
                       select itemGroup.Key;
        }

        /// <summary>
        /// Get all the duplicates in the specified collection based on the group by expresison
        /// </summary>
        /// <typeparam name="TOwner">The type of the owner.</typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="groupByExpression">The group by expression.</param>
        /// <returns></returns>
        public static IEnumerable<TOwner> Duplicates<TOwner>(this IEnumerable<TOwner> collection, Func<TOwner, object> groupByExpression)
        {
            return (from o in collection
                    group o by groupByExpression(o)
                    into g
                        where g.Count() > 1
                        select g).SelectMany(a => a);
        }

        /// <summary>
        /// Gets the keys.
        /// </summary>
        /// <typeparam name="TKey">The type of the key.</typeparam>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="item">The item.</param>
        /// <returns></returns>
        public static List<TKey> GetKeys<TKey, TItem>(this IEnumerable<KeyValuePair<TKey, TItem>> collection, TItem item)
        {
            return collection.Where(x => Equals(x.Value, item)).Select(x => x.Key).ToList();
        }

        /// <summary>
        /// Isolates the specified list.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <returns></returns>
        public static IEnumerable Isolate(this IEnumerable list)
        {
            return new IteratorIsolate(list);
        }

        
        public static string ToDelimitedString<T>(this IList<T> source, string delimiter)
        {
            source.CheckNull("source");
            delimiter.CheckNull("delimiter");
            StringBuilder stringBuilder = new StringBuilder();
            for (int i=0; i<source.Count; i++)
            {
                stringBuilder.Append(source[i]);
                if (i < (source.Count-1))
                {
                    stringBuilder.Append(delimiter);
                }
            }

            return stringBuilder.ToString();
        }
    }
}